#include <Python.h>

#include <iostream>
#include <string>

int main(int argc, char *argv[])
{
    std::string pyFilePath = "calc";
    if (argc > 1)
    {
        pyFilePath = argv[1];
    }

    Py_Initialize();

    PyObject *pModule = PyImport_ImportModule(pyFilePath.data());
    if (!pModule)
    {
        PyErr_Print();
        Py_Finalize();
        return 1;
    }

    // Get Python function object "my_python_function"
    PyObject *pFunc = PyObject_GetAttrString(pModule, "to_string");
    if (!pFunc)
    {
        PyErr_Print();
        Py_DECREF(pModule);
        Py_Finalize();
        return 1;
    }

    // Convert C++ arguments to Python objects
    long arg1 = 100;
    PyObject *pArg1 = PyLong_FromLong(arg1);

    long arg2 = 999;
    PyObject *pArg2 = PyLong_FromLong(arg2);

    std::string arg3 = "Tiffany";
    PyObject *pArg3 = PyUnicode_FromString(arg3.c_str());
    // PyObject *pArg3 = PyUnicode_FromString("Hello, World!");

    // Construct a dictionary for keyword arguments
    // PyObject *pKeywords = PyDict_New();
    // PyDict_SetItemString(pKeywords, "arg2", pArg2);

    // Create a tuple to hold the Python arguments
    PyObject *pArgs = PyTuple_New(3);
    PyTuple_SetItem(pArgs, 0, pArg1);
    PyTuple_SetItem(pArgs, 1, pArg2);
    PyTuple_SetItem(pArgs, 2, pArg3);

    // Call Python function and get the result
    // PyObject *pResult = PyEval_CallObjectWithKeywords(pFunc, pArgs, NULL);
    PyObject *pResult = PyObject_CallObject(pFunc, pArgs);
    if (!pResult)
    {
        PyErr_Print();
        Py_DECREF(pArgs);
        Py_DECREF(pFunc);
        Py_DECREF(pModule);
        Py_Finalize();
        return 1;
    }

    // Check if the result is an integer
    /**
    if (PyLong_Check(pResult))
    {
        long result = PyLong_AsLong(pResult);
        std::cout << "Python function returned: " << result << std::endl;
    }
    else
    {
        std::cout << "Python function returned an unexpected type." << std::endl;
    }
    */

    if (PyUnicode_Check(pResult))
    {
        std::string result = PyUnicode_AsUTF8(pResult);
        std::cout
            << "Pytho result = " << result << '\n';
    }
    else
    {
        std::cout << "Python function returned an unexpected type." << std::endl;
    }

    // Clean up and finalize
    Py_DECREF(pResult);
    Py_DECREF(pArgs);
    Py_DECREF(pFunc);
    Py_DECREF(pModule);
    Py_Finalize(); // Finalize the Python interpreter
    return 0;
}